home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue44 / HTMLmove / newparse.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1998-10-31  |  16.3 KB  |  623 lines

  1. { *****************************************************
  2.                  NewParse Unit
  3.  
  4.                   Paul Warren
  5.          HomeGrown Software Development
  6.        (c) 1997 Langley British Columbia.
  7.                 (604) 856-6523
  8.          e-mail:  hg_soft@uniserve.com
  9.     Home page: http://users.uniserve.com/~hg_soft
  10.   ***************************************************** }
  11.  
  12. unit Newparse;
  13. { $DEFINE DEBUG}
  14.  
  15. interface
  16.  
  17. uses Classes, Consts, SysUtils, Dialogs;
  18.  
  19. type
  20.   TParserClass = class of TCustomParser;
  21.  
  22.   TCustomParser = class
  23.   private
  24.     { private declarations }
  25.     FStream: TStream;
  26.     FOrigin: Longint;
  27.     FBuffer: PChar;
  28.     FBufPtr: PChar;
  29.     FBufEnd: PChar;
  30.     FSourcePtr: PChar;
  31.     FSourceEnd: PChar;
  32.     FTokenPtr: PChar;
  33.     FStringPtr: PChar;
  34.     FSourceLine: Integer;
  35.     FSaveChar: Char;
  36.     FToken: Char;
  37.     procedure ReadBuffer;
  38.     procedure SkipBlanks;
  39.     {$IFDEF Win32}
  40.     procedure Error(const Ident: string); virtual;
  41.     {$ELSE}
  42.     procedure Error(MessageID: Word); virtual;
  43.     {$ENDIF}
  44.     procedure ErrorStr(const Message: string);
  45.   public
  46.     { public declarations }
  47.     constructor Create(Stream: TStream); virtual;
  48.     destructor Destroy; override;
  49.     function NextToken: Char; virtual;
  50.     function TokenString: string; virtual;
  51.     function SourcePos: Longint;
  52.     property Token: Char read FToken;
  53.     property SourceLine: integer read FSourceLine;
  54.   end;
  55.  
  56.   TCSVParser = class(TCustomParser)
  57.   private
  58.     { private declarations }
  59.   public
  60.     { public declarations }
  61.     function TokenString: string; override;
  62.     function NextToken: char; override;
  63.   end;
  64.  
  65.   TTextParser = class(TCustomParser)
  66.   private
  67.     { private declarations }
  68.   public
  69.     { public declarations }
  70.     function NextToken: Char; override;
  71.   end;
  72.  
  73.   TPasParser = class(TTextParser)
  74.   private
  75.     { private declarations }
  76.   public
  77.     { public declarations }
  78.     function NextToken: Char; override;
  79.   end;
  80.  
  81. const
  82.   toComment = Char(5);
  83.  
  84. type
  85.   TEnhPasParser = class(TPasParser)
  86.   private
  87.     { private declarations }
  88.   public
  89.     { public declarations }
  90.     function TokenString: string; override;
  91.     function NextToken: Char; override;
  92.   end;
  93.  
  94. const
  95.   toOpenTag = Char(6);
  96.   toCloseTag = Char(7);
  97.  
  98. type
  99.   THtmlParser = class(TTextParser)
  100.   private
  101.     { private declarations }
  102.   public
  103.     { public declarations }
  104.     function TokenString: string; override;
  105.     function NextToken: Char; override;
  106.   end;
  107.  
  108. var
  109.   Log: TextFile;
  110.  
  111. implementation
  112.  
  113. const
  114.   ParseBufSize: integer = 4096;
  115.  
  116. { TCustomParser }
  117. constructor TCustomParser.Create(Stream: TStream);
  118. begin
  119.   FStream := Stream;
  120.   GetMem(FBuffer, ParseBufSize);
  121.   FBuffer[0] := #0;
  122.   FBufPtr := FBuffer;
  123.   FBufEnd := FBuffer + ParseBufSize;
  124.   FSourcePtr := FBuffer;
  125.   FSourceEnd := FBuffer;
  126.   FTokenPtr := FBuffer;
  127.   FSourceLine := 1;
  128.   {$IFDEF DEBUG}
  129.   writeln(log,'');
  130.   writeln(log, 'FBuffer FBufPtr FSrcPtr   FSrcEnd FBufEnd Pos Occured');
  131.   writeln(log,'');
  132.   writeln(log,LongInt(FBuffer), ' ', LongInt(FBufPtr), ' ', LongInt(FSourcePtr),' ', FSourcePtr^, ' ', LongInt(FSourceEnd), ' ', LongInt(FBufEnd), ' ',FStream.Position,' on create');
  133.   {$ENDIF}
  134.   NextToken;
  135. end;
  136.  
  137. destructor TCustomParser.Destroy;
  138. begin
  139.   if FBuffer <> nil then
  140.   begin
  141.     FStream.Seek(Longint(FTokenPtr) - Longint(FSourceEnd), 1);
  142.     FreeMem(FBuffer, ParseBufSize);
  143.   end;
  144. end;
  145.  
  146. procedure TCustomParser.ReadBuffer;
  147. var
  148.   Count: Integer;
  149. begin
  150.   try
  151.     Inc(FOrigin, FSourcePtr - FBuffer);
  152.     FSourceEnd[0] := FSaveChar;
  153.   {$IFDEF DEBUG}
  154.     writeln(log,LongInt(FBuffer), ' ', LongInt(FBufPtr), ' ', LongInt(FSourcePtr),' ', FSourcePtr^,' ', LongInt(FSourceEnd),' ',LongInt(FBufEnd), ' ',FStream.Position, ' before read');
  155.   {$ENDIF}
  156.     Count := FBufPtr - FSourcePtr;
  157.     if Count <> 0 then Move(FSourcePtr[0], FBuffer[0], Count);
  158.     FBufPtr := FBuffer + Count;
  159.     Inc(FBufPtr, FStream.Read(FBufPtr[0], FBufEnd - FBufPtr));
  160.   {$IFDEF DEBUG}
  161.     writeln(log,LongInt(FBuffer), ' ', LongInt(FBufPtr), ' ', LongInt(FSourcePtr),' ', FSourcePtr^, ' ', LongInt(FSourceEnd), ' ', LongInt(FBufEnd), ' ',FStream.Position, ' after read');
  162.   {$ENDIF}
  163.     FSourcePtr := FBuffer;
  164.     FSourceEnd := FBufPtr;
  165.     if FSourceEnd = FBufEnd then
  166.     begin
  167.       FSourceEnd := LineStart(FBuffer, FSourceEnd - 1);
  168.       if FSourceEnd = FBuffer then Error(SLineTooLong);
  169.     end;
  170.     FSaveChar := FSourceEnd[0];
  171.     FSourceEnd[0] := #0;
  172.   except
  173.     on EStreamError do
  174.       MessageDlg('FSourcePtr^ = '+FSourcePtr^,mtError,
  175.         [mbOK],0);
  176.     on EAccessViolation do
  177.       MessageDlg('FSourcePtr^ = '+FSourcePtr^,mtError,
  178.         [mbOK],0);
  179.   end;
  180. end;
  181.  
  182. function TCustomParser.NextToken: Char;
  183. begin
  184.   FToken := FSourcePtr^;
  185.   if FToken <> toEOF then Inc(FSourcePtr);
  186.   Result := FToken;
  187. end;
  188.  
  189. procedure TCustomParser.SkipBlanks;
  190. begin
  191.   while True do
  192.   begin
  193.     case FSourcePtr^ of
  194.       #0:
  195.         begin
  196.           ReadBuffer;
  197.           if FSourcePtr^ = #0 then Exit;
  198.           Continue;
  199.         end;
  200.       #10:
  201.         Inc(FSourceLine);
  202.       #33..#255:
  203.         Exit;
  204.     end;
  205.     Inc(FSourcePtr);
  206.   end;
  207. end;
  208.  
  209. function TCustomParser.TokenString: string;
  210. var
  211.   L: Integer;
  212. begin
  213.   if (FToken = toString) then
  214.     L := FStringPtr - FTokenPtr else
  215.     L := FSourcePtr - FTokenPtr;
  216.   {$IFDEF Win32}
  217.   SetString(Result, FTokenPtr, L);
  218.   {$ELSE}
  219.   if L > 255 then L := 255;
  220.   Result[0] := Char(L);
  221.   {$ENDIF}
  222.   Move(FTokenPtr[0], Result[1], L);
  223. end;
  224.  
  225. {$IFDEF Win32}
  226. procedure TCustomParser.Error(const Ident: string);
  227. begin
  228.   ErrorStr(Ident);
  229. end;
  230.  
  231. procedure TCustomParser.ErrorStr(const Message: string);
  232. begin
  233.   raise EParserError.CreateFmt(SParseError, [Message, FSourceLine]);
  234. end;
  235. {$ELSE}
  236. procedure TCustomParser.Error(MessageID: Word);
  237. begin
  238.   ErrorStr(LoadStr(MessageID));
  239. end;
  240.  
  241. procedure TCustomParser.ErrorStr(const Message: string);
  242. begin
  243.   raise EParserError.Create(FmtLoadStr(SParseError, [Message, FSourceLine]));
  244. end;
  245. {$ENDIF}
  246.  
  247. function TCustomParser.SourcePos: Longint;
  248. begin
  249.   Result := FOrigin + (FTokenPtr - FBuffer);
  250. end;
  251.  
  252. { TCSVParser }
  253. function TCSVParser.TokenString: string;
  254. var
  255.   L: Integer;
  256. begin
  257.   if (FToken = toSymbol) then
  258.     L := FStringPtr - FTokenPtr else
  259.     L := FSourcePtr - FTokenPtr;
  260.   {$IFDEF Win32}
  261.   SetString(Result, FTokenPtr, L);
  262.   {$ELSE}
  263.   if L > 255 then L := 255;
  264.   Result[0] := Char(L);
  265.   {$ENDIF}
  266.   Move(FTokenPtr[0], Result[1], L);
  267. end;
  268.  
  269. function TCSVParser.NextToken: Char;
  270. begin
  271.   SkipBlanks;
  272.   FTokenPtr := FSourcePtr;
  273.   case FSourcePtr^ of
  274.     'A'..'Z', 'a'..'z', '_':
  275.       begin
  276.         Inc(FSourcePtr);
  277.         FStringPtr := FSourcePtr;
  278.         while true do
  279.         begin
  280.           case FSourcePtr^ of
  281.             ',': Break;
  282.             #0: Break;
  283.           end;
  284.           FStringPtr^ := FSourcePtr^;
  285.           Inc(FStringPtr);
  286.           Inc(FSourcePtr);
  287.         end;
  288.         FToken := toSymbol;
  289.         Result := FToken;
  290.       end;
  291.     '-', '0'..'9':
  292.       begin
  293.         Inc(FSourcePtr);
  294.         while FSourcePtr^ in ['0'..'9'] do Inc(FSourcePtr);
  295.         FToken := toInteger;
  296.         Result := FToken;
  297.         while FSourcePtr^ in ['0'..'9', '.', 'e', 'E', '+', '-'] do
  298.         begin
  299.           Inc(FSourcePtr);
  300.           FToken := toFloat;
  301.           Result := FToken;
  302.         end;
  303.       end;
  304.     else Result := inherited NextToken;
  305.   end;
  306. end;
  307.  
  308. { TTextParser }
  309. function TTextParser.NextToken: Char;
  310. begin
  311.   SkipBlanks;
  312.   FTokenPtr := FSourcePtr;
  313.   case FSourcePtr^ of
  314.     'A'..'Z', 'a'..'z', '_':
  315.       begin
  316.         Inc(FSourcePtr);
  317.         while True do
  318.           case FSourcePtr^ of
  319.             'A'..'Z', 'a'..'z', '0'..'9', '_': Inc(FSourcePtr);
  320.             '''': begin  { apostrophies }
  321.                 if (FSourcePtr+1)^ in ['A'..'Z', 'a'..'z', '0'..'9', '_'] then Inc(FSourcePtr)
  322.                 else Break;
  323.               end;
  324.             '-': begin  { hyphenated words }
  325.                 if (FSourcePtr+1)^ in ['A'..'Z', 'a'..'z', '0'..'9', '_'] then Inc(FSourcePtr)
  326.                 else Break;
  327.               end;
  328.             else Break;
  329.           end;
  330.         FToken := toSymbol;
  331.         Result := FToken;
  332.       end;
  333.     '-', '0'..'9':
  334.       begin
  335.         Inc(FSourcePtr);
  336.         while FSourcePtr^ in ['0'..'9'] do Inc(FSourcePtr);
  337.         FToken := toInteger;
  338.         Result := FToken;
  339.         while FSourcePtr^ in ['0'..'9', '.', 'e', 'E', '+', '-'] do
  340.         begin
  341.           Inc(FSourcePtr);
  342.           FToken := toFloat;
  343.           Result := FToken;
  344.         end;
  345.       end;
  346.     else Result := inherited NextToken;
  347.   end;
  348. end;
  349.  
  350. { TPasParser }
  351. function TPasParser.NextToken: Char;
  352. var
  353.   I: integer;
  354. begin
  355.   SkipBlanks;
  356.   FTokenPtr := FSourcePtr;
  357.   case FSourcePtr^ of
  358.     'A'..'Z', 'a'..'z', '_':
  359.       begin
  360.         Inc(FSourcePtr);
  361.         while FSourcePtr^ in ['A'..'Z', 'a'..'z', '0'..'9', '_'] do Inc(FSourcePtr);
  362.         FToken := toSymbol;
  363.         Result := FToken;
  364.       end;
  365.     '#', '''':
  366.       begin
  367.         FStringPtr := FSourcePtr;
  368.         while True do
  369.           case FSourcePtr^ of
  370.             '#':
  371.               begin
  372.                 Inc(FSourcePtr);
  373.                 I := 0;
  374.                 while FSourcePtr^ in ['0'..'9'] do
  375.                 begin
  376.                   I := I * 10 + (Ord(FSourcePtr^) - Ord('0'));
  377.                   Inc(FSourcePtr);
  378.                 end;
  379.                 FStringPtr^ := Chr(I);
  380.                 Inc(FStringPtr);
  381.               end;
  382.             '''':
  383.               begin
  384.                 Inc(FSourcePtr);
  385.                 while True do
  386.                 begin
  387.                   case FSourcePtr^ of
  388.                     #0, #10, #13:
  389.                       Error(SInvalidString);
  390.                     '''':
  391.                       begin
  392.                         Inc(FSourcePtr);
  393.                         if FSourcePtr^ <> '''' then Break;
  394.                       end;
  395.                   end;
  396.                   FStringPtr^ := FSourcePtr^;
  397.                   Inc(FStringPtr);
  398.                   Inc(FSourcePtr);
  399.                 end;
  400.               end;
  401.           else
  402.             Break;
  403.           end;
  404.         FToken := toString;
  405.         Result := FToken;
  406.       end;
  407.     '$':
  408.       begin
  409.         FToken := FSourcePtr^;  { assume NOT an integer }
  410.         Result := FToken;
  411.         Inc(FSourcePtr);
  412.         while true do
  413.         begin
  414.           case FSourcePtr^ of
  415.             '0'..'9', 'A'..'F', 'a'..'f': Inc(FSourcePtr);
  416.             else Break;
  417.           end;
  418.           FToken := toInteger;
  419.           Result := FToken;
  420.         end;
  421.       end;
  422.   (*  '-', '0'..'9':
  423.       begin
  424.         Inc(FSourcePtr);
  425.         while FSourcePtr^ in ['0'..'9'] do Inc(FSourcePtr);
  426.         FToken := toInteger;
  427.         Result := FToken;
  428.         while FSourcePtr^ in ['0'..'9', '.', 'e', 'E', '+', '-'] do
  429.         begin
  430.           Inc(FSourcePtr);
  431.           FToken := toFloat;
  432.           Result := FToken;
  433.         end;
  434.       end;  *)
  435.     else Result := inherited NextToken;
  436.   end;
  437. end;
  438.  
  439. { TEnhPasParser }
  440. function TEnhPasParser.TokenString: string;
  441. var
  442.   L: Integer;
  443. begin
  444.   if (FToken = toString) or (FToken = toComment) then
  445.     L := FStringPtr - FTokenPtr else
  446.     L := FSourcePtr - FTokenPtr;
  447.   {$IFDEF Win32}
  448.   SetString(Result, FTokenPtr, L);
  449.   {$ELSE}
  450.   if L > 255 then L := 255;
  451.   Result[0] := Char(L);
  452.   {$ENDIF}
  453.   Move(FTokenPtr[0], Result[1], L);
  454. end;
  455.  
  456. function TEnhPasParser.NextToken: Char;
  457. begin
  458.   SkipBlanks;
  459.   FTokenPtr := FSourcePtr;
  460.   case FSourcePtr^ of
  461.     '{':
  462.       begin { comment or compiler directive... }
  463.         FStringPtr := FSourcePtr;
  464.         Inc(FSourcePtr);  { check next char... }
  465.         while true do
  466.         begin
  467.           case FSourcePtr^ of
  468.             #0: begin
  469.               ReadBuffer;
  470.               FStringPtr := FSourcePtr;
  471.               if FSourcePtr^ = #0 then Break;
  472.               {$IFDEF DEBUG}
  473.               writeln(Log, 'in comment');
  474.               {$ENDIF}
  475.             end;
  476.             #10: Inc(FSourceLine);
  477.             '}':
  478.               begin
  479.                 Inc(FSourcePtr);
  480.                 Break;      { end comment... }
  481.               end;
  482.           end;
  483.           FStringPtr^ := FSourcePtr^;
  484.           Inc(FStringPtr);
  485.           Inc(FSourcePtr);
  486.         end;
  487.         FToken := toComment;
  488.         Result := FToken;
  489.       end;
  490.     '(', '/':  { possible comment or compiler directive... }
  491.       begin
  492.         FToken := FSourcePtr^; { assume NOT a comment }
  493.         Result := FToken;
  494.         FStringPtr := FSourcePtr;
  495.         Inc(FSourcePtr);  { check next char... }
  496.         case FSourcePtr^ of
  497.           '*':  { is a comment }
  498.             begin
  499.               Inc(FSourcePtr);  { check next char... }
  500.               while True do
  501.               begin
  502.                 case FSourcePtr^ of
  503.                   #0: begin
  504.                     ReadBuffer;
  505.                     FStringPtr := FSourcePtr;
  506.                     if FSourcePtr^ = #0 then Break;
  507.                     {$IFDEF DEBUG}
  508.                     writeln(Log, 'in comment');
  509.                     {$ENDIF}
  510.                   end;
  511.                   #10: Inc(FSourceLine);
  512.                   '*':
  513.                     begin
  514.                       Inc(FSourcePtr);
  515.                       if FSourcePtr^ = ')' then
  516.                       begin
  517.                         Inc(FSourcePtr);
  518.                         Break; { end of comment }
  519.                       end;
  520.                     end;
  521.                 end;
  522.                 FStringPtr^ := FSourcePtr^;
  523.                 Inc(FStringPtr);
  524.                 Inc(FSourcePtr);
  525.               end;
  526.               FToken := toComment;
  527.               Result := FToken;
  528.             end;
  529.           '/':  { is a comment }
  530.             begin
  531.               Inc(FSourcePtr);
  532.               while (FSourcePtr^ <> #13) do  { end of line, hence comment }
  533.               begin
  534.                 FStringPtr^ := FSourcePtr^;
  535.                 Inc(FStringPtr);
  536.                 Inc(FSourcePtr);
  537.               end;
  538.               FToken := toComment;
  539.               Result := FToken;
  540.             end;
  541.         end;
  542.       end;
  543.     else Result := inherited NextToken;
  544.   end;
  545. end;
  546.  
  547. { THtmlParser }
  548. function THtmlParser.TokenString: string;
  549. var
  550.   L: Integer;
  551. begin
  552.   if (FToken = toString) or (FToken = toOpenTag)
  553.     or (FToken = toCloseTag) then
  554.       L := FStringPtr - FTokenPtr else
  555.       L := FSourcePtr - FTokenPtr;
  556.   {$IFDEF Win32}
  557.   SetString(Result, FTokenPtr, L);
  558.   {$ELSE}
  559.   if L > 255 then L := 255;
  560.   Result[0] := Char(L);
  561.   {$ENDIF}
  562.   Move(FTokenPtr[0], Result[1], L);
  563. end;
  564.  
  565. function THtmlParser.NextToken: Char;
  566. begin
  567.   SkipBlanks;
  568.   FTokenPtr := FSourcePtr;
  569.   case FSourcePtr^ of
  570.     '<':   { is a tag }
  571.     begin
  572.       FStringPtr := FSourcePtr;
  573.       Inc(FSourcePtr);
  574.       case FSourcePtr^ of
  575.         '/':  { is an 'close' tag }
  576.           begin
  577.             Inc(FSourcePtr);
  578.             while true do
  579.             begin
  580.               case FSourcePtr^ of
  581.                 #0: begin
  582.                   ReadBuffer;
  583.                   FStringPtr := FSourcePtr;
  584.                   if FSourcePtr^ = #0 then Break;
  585.                 end;
  586.                 '>': begin
  587.                   Inc(FSourcePtr);
  588.                   Break; { end of tag }
  589.                 end;
  590.               end; {case}
  591.               FStringPtr^ := FSourcePtr^;
  592.               Inc(FStringPtr);
  593.               Inc(FSourcePtr);
  594.             end;
  595.             FToken := toCloseTag;
  596.             Result := FToken;
  597.           end;
  598.         else
  599.           begin
  600.             while true do
  601.             begin
  602.               case FSourcePtr^ of
  603.                 #0: begin
  604.                   ReadBuffer;
  605.                   FStringPtr := FSourcePtr;
  606.                   if FSourcePtr^ = #0 then Break;
  607.                 end;
  608.                 '>': begin
  609.                   Inc(FSourcePtr);
  610.                   Break; { end of tag }
  611.                 end;
  612.               end; {case}
  613.               FStringPtr^ := FSourcePtr^;
  614.               Inc(FStringPtr);
  615.               Inc(FSourcePtr);
  616.             end;
  617.             FToken := toOpenTag;
  618.             Result := FToken;
  619.           end;
  620.       end; {case}
  621.     end;
  622.     else Result := inherited NextToken;
  623.   end;
  624. end;
  625.  
  626. {$IFDEF DEBUG}
  627. initialization
  628.   AssignFile(Log, 'debug.log');
  629.   Rewrite(Log);
  630. finalization
  631.   CloseFile(Log);
  632. {$ENDIF}
  633. end.
  634.